#pragma once

#include<iostream>
#include<ctime>
#include<cstring>
#include<stdio.h>
#include<string>
#include<stdarg.h>
#include<unistd.h>
#include<typeinfo>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>

using namespace std;

#define LogFile "log.txt"
#define SIZE 1024

#define Screen      1
#define OneFile     2
#define ClassFile   3

#define Info    1
#define Debug   2
#define Warning 3
#define Error   4
#define Fatal   5

class Log{
public:
    Log()
        :_printMethod(Screen)
        ,_path("./log/")
    {}

    void Enable(int method){
        _printMethod=method;
    }

    string LevelToString(int level){
        switch(level){
            case Info:
                return "Info";
            case Debug:
                return "Debug";
            case Warning:
                return "Warning";
            case Error:
                return "Error";
            case Fatal:
                return "Fatal";
            default:
                return "None";
        }
    }

    void PrintLog(int level,const string& logtxt){
        switch(_printMethod){
            case Screen:
                cout<<logtxt;
                break;
            case OneFile:
                PrintOneFile(LogFile,logtxt);
                break;
            case ClassFile:
                PrintClassFile(level,logtxt);
            default:
                break;
        }
    }

    void PrintOneFile(const string& logname,const string& logtxt){
        mkdir(_path.c_str(),0666);
        string pathname=_path+logname;
        int fd=open(pathname.c_str(),O_CREAT|O_WRONLY|O_APPEND,0666);
        if(fd==-1) return ;
        write(fd,logtxt.c_str(),logtxt.size());
        close(fd);
    }

    void PrintClassFile(int level,const string& logtxt){
        string filename=LogFile;
        filename+=".";
        filename+=LevelToString(level);
        PrintOneFile(filename,logtxt);
    }

    void operator()(int level,const char* format,...){
         char LeftBuffer[SIZE]={0};
         time_t tm=time(nullptr);
         struct tm* t=localtime(&tm);
         snprintf(LeftBuffer,sizeof(LeftBuffer),"[%s][%d-%d-%d %d:%d:%d]:",LevelToString\
         (level).c_str(),t->tm_year+1900,t->tm_mon+1,t->tm_mday,t->tm_hour,t->tm_min,t->tm_sec);
        char RightBuffer[SIZE]={0};
        va_list ap;
        va_start(ap,format);
        vsnprintf(RightBuffer,sizeof(RightBuffer),format,ap);
        va_end(ap);
        char TxtBuffer[2*SIZE]={0};
        snprintf(TxtBuffer,sizeof(TxtBuffer),"%s %s\n",LeftBuffer,RightBuffer);
        PrintLog(level,TxtBuffer);
    }

    ~Log(){

    }
protected:
    int _printMethod;
    string _path;
};

// int Add(int n,...){
//     va_list v;//char* 
//     va_start(v,n);
//     cout<<typeid(v).name()<<endl;
//     int sum=0;
//     while(n){
//         sum+=va_arg(v,int);
//         --n;
//     }
//     va_end(v);//v==NULL
//     return sum;
// }